<!doctype html>
<!--
@license
Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
Code distributed by Google as part of the polymer project is also
subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
-->
<html>
<head>
  <meta charset="utf-8">
  <script src="../../../webcomponentsjs/webcomponents-lite.js"></script>
  <script src="../../../web-component-tester/browser.js"></script>
  <link rel="import" href="../../polymer.html">
</head>
<body>

  <x-scope></x-scope>

  <dom-module id="x-grand-child-scope">
    <style>
      :host {
        display: block;
        padding: 8px;
      }

      #scope {
        border: var(--scope-var);
      }

      #child {
        border: var(--child-scope-var);
      }

      #me {
        border: var(--grand-child-scope-var);
      }

    </style>

    <template>
      <div id="me">x-grand-child-scope</div>
      <div id="scope">From x-scope</div>
      <div id="child">From x-child-scope</div>
    </template>
    <script>
    HTMLImports.whenReady(function() {
      Polymer({is: 'x-grand-child-scope'});
    });
    </script>
  </dom-module>

  <dom-module id="x-host-property">
    <style>
      :host {
        display: block;
        padding: 8px;
        border: var(--scope-var);
      }
    </style>

    <template>
      Host property
    </template>
    <script>
    HTMLImports.whenReady(function() {
      Polymer({is: 'x-host-property'});
    });
    </script>
  </dom-module>

  <dom-module id="x-child-scope">
    <style>
      :host {
        display: block;
        padding: 8px;
      }

      :root {
        --gc4-scope: 5px solid green;
      }

      #me {
        border: var(--child-scope-var);
      }

      #gc2 {
        --grand-child-scope-var: 4px solid seagreen;
      }

      #gc4 {
        --grand-child-scope-var: var(--gc4-scope);
      }
    </style>

    <template>
      <div id="me">x-child-scope</div>
      <x-grand-child-scope id="gc1"></x-grand-child-scope>
      <x-grand-child-scope id="gc2"></x-grand-child-scope>
      <x-grand-child-scope id="gc3"></x-grand-child-scope>
      <x-grand-child-scope id="gc4"></x-grand-child-scope>
    </template>
    <script>
    HTMLImports.whenReady(function() {
      Polymer({is: 'x-child-scope'});
    });
    </script>
  </dom-module>

  <dom-module id="x-overrides">
    <style>
      :host {
        border: 1px dashed gray;
        margin: 8px;
        padding: 8px;
        display: block;
        --grand-child-scope-var: var(--rename);
      }
    </style>

    <template>
      overrides:
      <x-grand-child-scope id="gc1"></x-grand-child-scope>
    </template>
    <script>
    HTMLImports.whenReady(function() {
      Polymer({is: 'x-overrides'});
    });
    </script>
  </dom-module>

  <dom-module id="x-overrides2">
    <style>
      :host {
        border: 1px dashed gray;
        margin: 8px;
        padding: 8px;
        display: block;
      }

      :root {
        --grand-child-scope-var: var(--rename);
      }
    </style>

    <template>
      overrides:
      <x-grand-child-scope id="gc1"></x-grand-child-scope>
    </template>
    <script>
    HTMLImports.whenReady(function() {
      Polymer({is: 'x-overrides2'});
    });
    </script>
  </dom-module>

  <dom-module id="x-has-if">
    <style>
      .iffy {
        border: var(--scope-var);
      }
    </style>

    <template>
      <template is="dom-if" if="{{gogo}}">
        <div class="iffy">iffy</div>
      </template>
    </template>
    <script>
    HTMLImports.whenReady(function() {
      Polymer({
        is: 'x-has-if',
        properties: {
          gogo: {value: true}
        }
      });
    });
    </script>
  </dom-module>
 
  <dom-module id="x-scope">
    <style>
      :host {
        x--invalid: 15px solid gray;
        display: block;
        padding: 8px;
        --scope-var: 1px solid black;
        --fallback: 7px solid orange;
        --default1: var(--undefined, 6px solid yellow);
        --default2: var(--undefined, --fallback);
        --default3: var(--undefined, rgb(128, 200, 250));
        --a: 10px;
        --b: 5px;
        --primary-color: rgb(128, 128, 128);
      }

      #me {
        border: var(--scope-var);
      }

      x-child-scope {
        --child-scope-var: 2px solid orange;
        --grand-child-scope-var: 3px solid steelblue;
      }

      x-child-scope.special {
        --child-scope-var: 12px solid orange;
      }

      #applyDefault1 {
        border: var(--undefined, 6px solid yellow);
      }

      #applyDefault2 {
        border: var(--undefined, --fallback);
      }

      #default1 {
        border: var(--default1);
      }

      #default2 {
        border: var(--default2);
      }

      #default3 {
        padding: 8px;
        background-color: var(--default3);
      }

      #overrides1, #overrides2, #overrides3 {
        --rename: 8px solid navy;
      }

      #overrides2, #overrides3 {
        --grand-child-scope-var: 9px solid orange;
      }

      #calc {
        border: solid red;
        border-width: calc(var(--a) + var(--b));
      }

      #shadow {
        box-shadow: 10px 10px 10px var(--primary-color);
        -webkit-box-shadow: 10px 10px 10px var(--primary-color);
      }

      x-host-property {
        border: 10px solid purple;
      }

      #invalid {
        border: var(--invalid);
      }
    </style>

    <template>
      <div id="me">x-scope</div>
      <x-child-scope id="child"></x-child-scope>
      <x-child-scope id="child2"></x-child-scope>
      <x-overrides id="overrides1"></x-overrides>
      <x-overrides id="overrides2"></x-overrides>
      <x-overrides2 id="overrides3"></x-overrides2>
      <div id="default1">default</div>
      <div id="default2">var default</div>
      <div id="default3">tricky property rgb(...) default</div>
      <div id="applyDefault1">default</div>
      <div id="applyDefault2">var default</div>
      <div id="calc">Calc</div>
      <div id="shadow">Shadow</div>
      <div id="invalid">invalid</div>
      <x-host-property id="hostProp"></x-host-property>
      <x-has-if id="iffy"></x-has-if>
    </template>
    <script>
    HTMLImports.whenReady(function() {
      Polymer({
        is: 'x-scope'
      });
    });
    </script>
  </dom-module>

<script>
  suite('scoped-styling-var', function() {

  function assertComputed(element, value) {
    var computed = getComputedStyle(element);
    assert.equal(computed['border-top-width'], value, 'computed style incorrect');
  }

  function assertStylePropertyValue(properties, name, includeValue) {
    assert.property(properties, name);
    assert.include(properties[name], includeValue);
  }

  var styled = document.querySelector('x-scope');

  test('simple variables calculated correctly between scopes', function() {
     assertStylePropertyValue(styled._styleProperties, '--scope-var', '1px');
     //
     var child = styled.$.child;
     assertStylePropertyValue(child._styleProperties, '--scope-var', '1px');
     assertStylePropertyValue(child._styleProperties, '--child-scope-var', '2px');
     assertStylePropertyValue(child._styleProperties, '--grand-child-scope-var', '3px');
     //
     var gc1 = child.$.gc1;
     assertStylePropertyValue(gc1._styleProperties, '--scope-var', '1px');
     assertStylePropertyValue(gc1._styleProperties, '--child-scope-var', '2px');
     assertStylePropertyValue(gc1._styleProperties, '--grand-child-scope-var', '3px');
     //
     var gc2 = child.$.gc2;
     assertStylePropertyValue(gc2._styleProperties, '--scope-var', '1px');
     assertStylePropertyValue(gc2._styleProperties, '--child-scope-var', '2px');
     assertStylePropertyValue(gc2._styleProperties, '--grand-child-scope-var', '4px');
     //
     var gc3 = child.$.gc3;
     assertStylePropertyValue(gc3._styleProperties, '--scope-var', '1px');
     assertStylePropertyValue(gc3._styleProperties, '--child-scope-var', '2px');
     assertStylePropertyValue(gc3._styleProperties, '--grand-child-scope-var', '3px');

  });

  test('invalid variables not parsed', function() {
    assert.notProperty(styled._styleProperties, 'x--invalid');
    assertComputed(styled.$.invalid, '0px');
  });

  test('simple variables applied correctly between scopes', function() {
     assertComputed(styled.$.me, '1px');
     assertComputed(styled.$.child.$.me, '2px');
     assertComputed(styled.$.child.$.gc1.$.me, '3px');
     assertComputed(styled.$.child.$.gc1.$.scope, '1px');
     assertComputed(styled.$.child.$.gc1.$.child, '2px');
     assertComputed(styled.$.child.$.gc2.$.me, '4px');
     assertComputed(styled.$.child.$.gc2.$.scope, '1px');
     assertComputed(styled.$.child.$.gc2.$.child, '2px');
  });

  test('variable can be set to another variable', function() {
    var gc4 = styled.$.child.$.gc4;
    assertStylePropertyValue(gc4._styleProperties, '--grand-child-scope-var', '5px');
    assertComputed(gc4.$.me, '5px');
  });

  test('variable default values can be assigned to other variables', function() {
    assertStylePropertyValue(styled._styleProperties, '--default1', '6px');
    assertStylePropertyValue(styled._styleProperties, '--default2', '7px');
    assertComputed(styled.$.default1, '6px');
    assertComputed(styled.$.default2, '7px');
    assertComputed(styled.$.applyDefault1, '6px');
    assertComputed(styled.$.applyDefault2, '7px');
  });

  test('variable literal defaults can contain one (...)', function() {
    var b = getComputedStyle(styled.$.default3).backgroundColor;
    assert.match(b, /rgb\(128/, 'literal fallback containin (...) not set');
  });

  test('variable values can be used with calc', function() {
    assertComputed(styled.$.calc, '15px');
  });

  test('variable values can be used with box-shadow', function() {
    var b = getComputedStyle(styled.$.shadow).boxShadow;
    assert.match(b, /rgb\(128/, 'box shadow not set correctly');
  });

  test('host properties can be overridden with outer scope styles', function() {
    assertComputed(styled.$.hostProp, '10px');
  });

  test('updateStyles changes property values and using style cache', function() {
    styled.$.child.classList.add('special');
    var l = document.querySelectorAll('style').length;
    styled.updateStyles();
    if (styled.shadyRoot) {
      assert.equal(document.querySelectorAll('style').length, l+4);
    }
    assertComputed(styled.$.child.$.me, '12px');
    styled.$.child.classList.remove('special');
    styled.updateStyles();
    if (styled.shadyRoot) {
      assert.equal(document.querySelectorAll('style').length, l);
    }
    assertComputed(styled.$.child.$.me, '2px');
  });

  test('style properties with dom-if', function() {
    var e = styled.$.iffy;
    var c = Polymer.dom(e.root).querySelector('.iffy');
    assert.ok(c, 'dom-if did not stamp');
    assertComputed(c, '1px');
  });

  test('variable precedence and overrides', function() {
    // renamed property applied
    var o1 = styled.$.overrides1;
    assertStylePropertyValue(o1._styleProperties, '--rename', '8px');
    assertStylePropertyValue(o1._styleProperties, '--grand-child-scope-var', '8px');
    assertComputed(o1.$.gc1.$.me, '8px');
    // :host property overridden by outer scope
    var o2 = styled.$.overrides2;
    assertStylePropertyValue(o2._styleProperties, '--rename', '8px');
    assertStylePropertyValue(o2._styleProperties, '--grand-child-scope-var', '9px');
    assertComputed(o2.$.gc1.$.me, '9px');
    // own scope property overrides outer scope
    var o3 = styled.$.overrides3;
    assertStylePropertyValue(o3._styleProperties, '--rename', '8px');
    assertStylePropertyValue(o3._styleProperties, '--grand-child-scope-var', '8px');
    assertComputed(o3.$.gc1.$.me, '8px');

  });
  
});

</script>
</body>
</html>
